<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
  <title>Coding Guidelines for Integral Constant Expressions</title>
  <meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
  <link rel="icon" href="/favicon.ico" type="image/ico" />
  <link rel="stylesheet" type="text/css" href=
  "/style-v2/section-development.css" />
  <!--[if IE 7]> <style type="text/css"> body { behavior: url(/style-v2/csshover3.htc); } </style> <![endif]-->
</head><!--
Note: Editing website content is documented at:
https://www.boost.org/development/website_updating.html
-->

<body>
  <div id="heading">
    <!--#include virtual="/common/heading.html" -->
  </div>

  <div id="body">
    <div id="body-inner">
      <div id="content">
        <div class="section" id="intro">
          <div class="section-0">
            <div class="section-title">
              <h1>Coding Guidelines for Integral Constant Expressions</h1>
            </div>

            <div class="section-body">
              <p>Integral Constant Expressions are used in many places in
              C++; as array bounds, as bit-field lengths, as enumerator
              initialisers, and as arguments to non-type template parameters.
              However many compilers have problems handling integral constant
              expressions; as a result of this, programming using non-type
              template parameters in particular can be fraught with
              difficulty, often leading to the incorrect assumption that
              non-type template parameters are unsupported by a particular
              compiler. This short article is designed to provide a set of
              guidelines and workarounds that, if followed, will allow
              integral constant expressions to be used in a manner portable
              to all the compilers currently supported by boost. Although
              this article is mainly targeted at boost library authors, it
              may also be useful for users who want to understand why boost
              code is written in a particular way, or who want to write
              portable code themselves.</p>

              <h2>What is an Integral Constant Expression?</h2>

              <p>Integral constant expressions are described in section 5.19
              of the standard, and are sometimes referred to as "compile time
              constants". An integral constant expression can be one of the
              following:</p>

              <ol>
                <li>A literal integral value, for example <code>0u</code> or
                <code>3L</code>.</li>

                <li>An enumerator value.</li>

                <li>Global integral constants, for example:
                  <pre>
const int my_INTEGRAL_CONSTANT = 3;
</pre>
                </li>

                <li>Static member constants, for example:
                  <pre>
struct myclass
{ static const int value = 0; };
</pre>
                </li>

                <li>Member enumerator values, for example:
                  <pre>
struct myclass
{ enum{ value = 0 }; };
</pre>
                </li>

                <li>Non-type template parameters of integral or enumerator
                type.</li>

                <li>The result of a <code>sizeof</code> expression, for
                example:
                  <pre>
sizeof(foo(a, b, c))
</pre>
                </li>

                <li>The result of a <code>static_cast</code>, where the
                target type is an integral or enumerator type, and the
                argument is either another integral constant expression, or a
                floating-point literal.</li>

                <li>The result of applying a binary operator to two integral
                constant expressions:
                  <pre>
INTEGRAL_CONSTANT1 op INTEGRAL_CONSTANT2
</pre>provided that the operator is not an assignment operator, or comma
operator.
                </li>

                <li>The result of applying a unary operator to an integral
                constant expression:
                  <pre>
op INTEGRAL_CONSTANT1
</pre>provided that the operator is not the increment or decrement operator.
                </li>
              </ol>

              <h2>Coding Guidelines</h2>

              <p>The following guidelines are declared in no particular order
              (in other words you need to obey all of them - sorry!), and may
              also be incomplete, more guidelines may be added as compilers
              change and/or more problems are encountered.</p>

              <h3>When declaring constants that are class members always use
              the macro <code>BOOST_STATIC_CONSTANT.</code></h3>
              <pre>
template &lt;class T&gt;
struct myclass
{
   BOOST_STATIC_CONSTANT(int, value = sizeof(T));
};
</pre>

              <p>Rationale: not all compilers support inline initialisation
              of member constants, others treat member enumerators in strange
              ways (they're not always treated as integral constant
              expressions). The BOOST_STATIC_CONSTANT macro uses the most
              appropriate method for the compiler in question.</p>

              <h3>Don't declare integral constant expressions whose type is
              wider than int.</h3>

              <p>Rationale: while in theory all integral types are usable in
              integral constant expressions, in practice many compilers limit
              integral constant expressions to types no wider than
              <code>int</code>.</p>

              <h3>Don't use logical operators in integral constant
              expressions; use template meta-programming instead.</h3>

              <p>The header <code>&lt;boost/type_traits/ice.hpp&gt;</code>
              contains a number of workaround templates, that fulfil the role
              of logical operators, for example instead of:</p>
              <pre>
INTEGRAL_CONSTANT1 || INTEGRAL_CONSTANT2
</pre>

              <p>Use:</p>
              <pre>
::boost::type_traits::ice_or&lt;INTEGRAL_CONSTANT1,INTEGRAL_CONSTANT2&gt;::value
</pre>

              <p>Rationale: A number of compilers (particularly the Borland
              and Microsoft compilers), tend to not to recognise integral
              constant expressions involving logical operators as genuine
              integral constant expressions. The problem generally only shows
              up when the integral constant expression is nested deep inside
              template code, and is hard to reproduce and diagnose.</p>

              <h3>Don't use any operators in an integral constant expression
              used as a non-type template parameter</h3>

              <p>Rather than:</p>
              <pre>
typedef myclass&lt;INTEGRAL_CONSTANT1 ==
              INTEGRAL_CONSTANT2&gt; mytypedef;
</pre>

              <p>Use:</p>
              <pre>
typedef myclass&lt; some_symbol&gt;
              mytypedef;
</pre>

              <p>Where <code>some_symbol</code> is the symbolic name of a an
              integral constant expression whose value is
              <code>(INTEGRAL_CONSTANT1 == INTEGRAL_CONSTANT2).</code></p>

              <p>Rationale: the older EDG based compilers (some of which are
              used in the most recent version of that platform's compiler),
              don't recognise expressions containing operators as non-type
              template parameters, even though such expressions can be used
              as integral constant expressions elsewhere.</p>

              <h3>Always use a fully qualified name to refer to an integral
              constant expression.</h3>

              <p>For example:</p>
              <pre>
<code>typedef</code> myclass&lt; ::boost::is_integral&lt;some_type&gt;::value&gt; mytypedef;
</pre>

              <p>Rationale: at least one compiler (Borland's), doesn't
              recognise the name of a constant as an integral constant
              expression unless the name is fully qualified (which is to say
              it starts with <code>::</code>).</p>

              <h3>Always leave a space after a '<code>&lt;</code>' and before
              '<code>::</code>'</h3>

              <p>For example:</p>
              <pre>
typedef myclass&lt; ::boost::is_integral&lt;some_type&gt;::value&gt; mytypedef;
                ^
                ensure there is space here!
</pre>

              <p>Rationale: <code>&lt;:</code> is a legal digraph in it's own
              right, so <code>&lt;::</code> is interpreted as the same as
              <code>[:</code>.</p>

              <h3>Don't use local names as integral constant expressions</h3>

              <p>Example:</p>
              <pre>
template &lt;class T&gt;
struct foobar
{
   BOOST_STATIC_CONSTANT(int, temp = computed_value);
   typedef myclass&lt;temp&gt; mytypedef;  // error
};
</pre>

              <p>Rationale: At least one compiler (Borland's) doesn't accept
              this.</p>

              <p>Although it is possible to fix this by using:</p>
              <pre>
template &lt;class T&gt;
struct foobar
{
   BOOST_STATIC_CONSTANT(int, temp = computed_value);
   typedef foobar self_type;
   typedef myclass&lt;(self_type::temp)&gt; mytypedef;  // OK
};
</pre>

              <p>This breaks at least one other compiler (VC6), it is better
              to move the integral constant expression computation out into a
              separate traits class:</p>
              <pre>
template &lt;class T&gt;
struct foobar_helper
{
   BOOST_STATIC_CONSTANT(int, value = computed_value);
};

template &lt;class T&gt;
struct foobar
{
   typedef myclass&lt; ::foobar_helper&lt;T&gt;::value&gt; mytypedef;  // OK
};
</pre>

              <h3>Don't use dependent default parameters for non-type
              template parameters.</h3>

              <p>For example:</p>
              <pre>
template &lt;class T, int I = ::boost::is_integral&lt;T&gt;::value&gt;  // Error can't deduce value of I in some cases.
struct foobar;
</pre>

              <p>Rationale: this kind of usage fails for Borland C++. Note
              that this is only an issue where the default value is dependent
              upon a previous template parameter, for example the following
              is fine:</p>
              <pre>
template &lt;class T, int I = 3&gt;  // OK, default value is not dependent
struct foobar;
</pre>

              <h2>Unresolved Issues</h2>

              <p>The following issues are either unresolved or have fixes
              that are compiler specific, and/or break one or more of the
              coding guidelines.</p>

              <h3>Be careful of numeric_limits</h3>

              <p>There are three issues here:</p>

              <ol>
                <li>The header &lt;limits&gt; may be absent - it is
                recommended that you never include &lt;limits&gt; directly
                but use &lt;boost/pending/limits.hpp&gt; instead. This header
                includes the "real" &lt;limits&gt; header if it is available,
                otherwise it supplies it's own std::numeric_limits
                definition. Boost also defines the macro BOOST_NO_LIMITS if
                &lt;limits&gt; is absent.</li>

                <li>The implementation of std::numeric_limits may be defined
                in such a way that its static-const members may not be usable
                as integral constant expressions. This contradicts the
                standard but seems to be a bug that affects at least two
                standard library vendors; boost defines
                BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS in
                &lt;boost/config.hpp&gt; when this is the case.</li>

                <li>There is a strange bug in VC6, where the members of
                std::numeric_limits can be "prematurely evaluated" in
                template code, for example:</li>
              </ol>
              <pre>
template &lt;class T&gt;
struct limits_test
{
   BOOST_STATIC_ASSERT(::std::numeric_limits&lt;T&gt;::is_specialized);
};
</pre>

              <p>This code fails to compile with VC6 even though no instances
              of the template are ever created; for some bizarre reason
              <code>::std::numeric_limits&lt;T&gt;::is_specialized</code>
              always evaluates to false, irrespective of what the template
              parameter T is. The problem seems to be confined to expressions
              which depend on std::numeric_limts: for example if you replace
              <code>::std::numeric_limits&lt;T&gt;::is_specialized</code>
              with <code>::boost::is_arithmetic&lt;T&gt;::value</code>, then
              everything is fine. The following workaround also works but
              conflicts with the coding guidelines:</p>
              <pre>
template &lt;class T&gt;
struct limits_test
{
   BOOST_STATIC_CONSTANT(bool, check = ::std::numeric_limits&lt;T&gt;::is_specialized);
   BOOST_STATIC_ASSERT(check);
};
</pre>

              <p>So it is probably best to resort to something like this:</p>
              <pre>
template &lt;class T&gt;
struct limits_test
{
#ifdef BOOST_MSVC
   BOOST_STATIC_CONSTANT(bool, check = ::std::numeric_limits&lt;T&gt;::is_specialized);
   BOOST_STATIC_ASSERT(check);
#else
   BOOST_STATIC_ASSERT(::std::numeric_limits&lt;T&gt;::is_specialized);
#endif
};
</pre>

              <h3>Be careful how you use the sizeof operator</h3>

              <p>As far as I can tell, all compilers treat sizeof expressions
              correctly when the argument is the name of a type (or a
              template-id), however problems can occur if:</p>

              <ol>
                <li>The argument is the name of a member-variable, or a local
                variable (code may not compile with VC6).</li>

                <li>The argument is an expression which involves the creation
                of a temporary (code will not compile with Borland C++).</li>

                <li>The argument is an expression involving an overloaded
                function call (code compiles but the result is a garbage
                value with Metroworks C++).</li>
              </ol>

              <h3>Don't use boost::is_convertible unless you have to</h3>

              <p>Since is_convertible is implemented in terms of the sizeof
              operator, it consistently gives the wrong value when used with
              the Metroworks compiler, and may not compile with the Borland's
              compiler (depending upon the template arguments used).</p>
            </div>
          </div>
        </div>
      </div>

      <div id="sidebar">
        <!--#include virtual="/common/sidebar-common.html" -->
        <!--#include virtual="/common/sidebar-development.html" -->
      </div>

      <div class="clear"></div>
    </div>
  </div>

  <div id="footer">
    <div id="footer-left">
      <div id="revised">
        <p>Revised $Date: 2007-10-22 22:55:52 +0100 (Mon, 22 Oct 2007) $</p>
      </div>

      <div id="copyright">
        <p>Copyright Dr John Maddock 2001.</p>
      </div><!--#include virtual="/common/footer-license.html" -->
    </div>

    <div id="footer-right">
      <!--#include virtual="/common/footer-banners.html" -->
    </div>

    <div class="clear"></div>
  </div>
</body>
</html>
